---
sidebar_position: 2
title: Socket Listening Guide
sidebar_label: Listening
---

# Listening to Events

In real-time applications, listening to events from a server is a core functionality. Hyper-fetch provides a simple and
powerful way to handle incoming socket events using `socket.createListener`. This allows you to define event listeners
that can be easily managed and integrated into your application, including React components.

---

:::secondary What you'll learn

1.  How to define an event listener using **`createListener`**.
2.  How to **start and stop** listening to events.
3.  How to **handle incoming data** from the socket.
4.  How to integrate socket listeners in React using the **`useListen` hook**.
5.  How to manage **multiple listeners** for the same event.

:::

## Creating a Listener

To start listening for events, you first need to create a listener. This is done using the `socket.createListener`
method, which requires an `endpoint` that corresponds to the event name you want to listen to. It's also a good practice
to provide a type for the expected message payload for type safety.

```ts
// highlight-start
// It is recommended to create a single listener instance and reuse it throughout your application.
// This helps to avoid re-creating listeners and attaching multiple handlers for the same event.
// highlight-end
const onChatMessage = socketInstance.createListener<{ message: string }>()({
  endpoint: "chat-message",
});
```

Here, we've created a listener for the `chat-message` event. The generic `<{ message: string }>` ensures that the data
received from this event will be correctly typed.

## Starting and Stopping

Once you have a listener, you can start listening for events by calling the `.listen()` method with a callback function.
This function will be executed every time a new message arrives on the specified endpoint.

The `.listen()` method returns an `unlisten` function, which you can call to stop listening for events. It's crucial to
call this cleanup function when the listener is no longer needed to prevent memory leaks.

```ts
const callback = (message) => {
  // highlight-next-line
  // The `message` parameter is fully typed based on the generic provided to `createListener`.
  console.log("New message received:", message.message);
};

// Start listening
const unlisten = onChatMessage.listen(callback);

// When you no longer need to listen for events, call the returned function.
// For example, in a web component's disconnectedCallback or a framework's unmount lifecycle.
unlisten();
```

---

## React Integration with `useListen`

For React applications, `@hyper-fetch/react` provides a `useListen` hook that simplifies the process of listening to
socket events within your components. It automatically handles starting and stopping the listener based on the
component's lifecycle.

The `useListen` hook takes the listener instance as its first argument and an object with an `onMessage` callback as the
second.

```tsx
function ChatComponent() {
  const [messages, setMessages] = React.useState([]);

  // highlight-start
  // The useListen hook manages the listener's lifecycle,
  // automatically calling listen() on mount and unlisten() on unmount.
  // highlight-end
  useListen(onChatMessage, {
    onMessage: (newMessage) => {
      setMessages((previousMessages) => [...previousMessages, newMessage]);
    },
  });

  return (
    <div className="p-4 border rounded-md w-full">
      <h3 className="text-lg font-bold mb-2">Live Chat</h3>
      <div className="h-48 overflow-y-auto bg-gray-100 dark:bg-gray-800 p-2 rounded-md space-y-2">
        {messages.length === 0 && (
          <p className="text-gray-500 dark:text-gray-400">No messages yet. Waiting for the server...</p>
        )}
        {messages.map((msg, index) => (
          <div key={index} className="bg-blue-100 dark:bg-blue-900 p-2 rounded-md">
            <p className="text-blue-800 dark:text-blue-200">{msg.message}</p>
          </div>
        ))}
      </div>
    </div>
  );
}
```

## Listening from Multiple Sources

You can use the `.listen()` method multiple times on the same listener instance. Each call will register a new callback,
and all of them will be executed when an event is received. Each `.listen()` call returns its own `unlisten` function,
allowing you to manage each listener independently.

```ts
const listenerOne = (message) => console.log("Listener 1:", message);
const listenerTwo = (message) => console.log("Listener 2:", message);

const unlistenOne = onChatMessage.listen(listenerOne);
const unlistenTwo = onChatMessage.listen(listenerTwo);

// To stop only the second listener:
unlistenTwo();

// To stop the first listener:
unlistenOne();
```

---

:::success Congratulations!

You now have a solid understanding of how to listen for socket events with Hyper-fetch.

- You can **create a typed listener** for any socket event.
- You know how to **start and stop listening** and the importance of cleaning up.
- You can integrate socket listeners into your **React components** effortlessly with the `useListen` hook.
- You are able to set up **multiple callbacks** for a single event and manage them independently.

:::
